package mylab.starters.generator.code.config;

import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.BeetlTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import freemarker.template.Template;
import lombok.RequiredArgsConstructor;
import mylab.base.constants.DbConst;
import mylab.starters.generator.code.CodeTemplate;
import org.apache.velocity.app.VelocityEngine;
import org.beetl.core.GroupTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import java.util.Collections;


@Configuration
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@EnableConfigurationProperties({CodeGeneratorProperties.class})
public class CodeGeneratorAutoConfiguration {


    private static final String[] SUPER_ENTITY_COLUMNS = new String[]{
            DbConst.COLUMN_ID,
            DbConst.COLUMN_CREATER,
            DbConst.COLUMN_UPDATER,
            DbConst.COLUMN_OWNER,
            DbConst.COLUMN_VERSION,
            DbConst.COLUMN_DELETED,
            DbConst.COLUMN_INVALID,
            DbConst.COLUMN_EXTRA};

    private static final String[] SUPER_DTO_COLUMNS = new String[]{
            DbConst.COLUMN_ID,
            DbConst.COLUMN_CREATER,
            DbConst.COLUMN_UPDATER,
            DbConst.COLUMN_OWNER,
            DbConst.COLUMN_VERSION,
            DbConst.COLUMN_DELETED,
            DbConst.COLUMN_INVALID,
            DbConst.COLUMN_EXTRA};

    private final CodeGeneratorProperties properties;

    private final DataSourceProperties dataSourceProperties;

    private final AbstractTemplateEngine templateEngine;

    @Bean("templateEngine")
    @Order(101)
    @ConditionalOnMissingBean
    @ConditionalOnClass({VelocityEngine.class})
    public AbstractTemplateEngine velocityEngine() {
        return new VelocityTemplateEngine();
    }

    @Bean("templateEngine")
    @Order(102)
    @ConditionalOnMissingBean
    @ConditionalOnClass({GroupTemplate.class})
    public AbstractTemplateEngine BeetlEngine() {
        return new BeetlTemplateEngine();
    }

    @Bean("templateEngine")
    @Order(103)
    @ConditionalOnMissingBean
    @ConditionalOnClass({Template.class})
    public AbstractTemplateEngine freemarkerEngine() {
        return new FreemarkerTemplateEngine();
    }

    @Bean
    public CodeTemplate codeTemplate() {

        return new CodeTemplate() {
            @Override
            public void generateCode(String author, String packageName, String moduleName, String projectPath) {

                String codePath = CharSequenceUtil.format("{}/src/main/java", projectPath);
                String xmlPath = CharSequenceUtil.format("{}/src/main/resources/mapper", projectPath);

                DataSourceConfig.Builder dataSourceConfig = new DataSourceConfig.Builder(
                        dataSourceProperties.getUrl(),
                        dataSourceProperties.getUsername(),
                        dataSourceProperties.getPassword());

                FastAutoGenerator
                        .create(dataSourceConfig)
                        .globalConfig(builder -> {
                            builder
                                    .fileOverride()
                                    .outputDir(codePath)
                                    .author(author)
                                    .enableSwagger()
                                    .dateType(DateType.TIME_PACK)
                                    .commentDate("yyyy-MM-dd");
                        })
                        .packageConfig(builder -> {
                            builder
                                    .parent(packageName)
                                    .moduleName(moduleName)
                                    .pathInfo(Collections.singletonMap(OutputFile.mapperXml, xmlPath));
                        })
                        //模板引擎三选一即可
                        .templateEngine(templateEngine)
                        .templateConfig(builder -> {
//                     自定义模板
//                    builder.controller("/templates/controller.java.vm");
//                    builder.disable(TemplateType.ENTITY);
                        })
                        .strategyConfig(builder -> {
                            builder
                                    .entityBuilder()
                                    .superClass(properties.getSuperEntityClass())
                                    .addSuperEntityColumns(SUPER_ENTITY_COLUMNS)
                                    .disableSerialVersionUID()
                                    .enableLombok()
                                    .enableColumnConstant()
                                    .enableTableFieldAnnotation()
                                    // entityBuilder  END
                                    .dtoBuilder()
                                    .superClass(properties.getSuperDtoClass())
                                    .addSuperEntityColumns(SUPER_DTO_COLUMNS)
                                    .formatDtoFileName("%sDTO")
                                    .enableLombok()
                                    // dtoBuilder  END
                                    .mapperBuilder()
                                    .superClass(properties.getSuperMapperClass())
//                            .enableMapperAnnotation()
//                            .enableBaseResultMap()
//                            .enableBaseColumnList()
                                    .formatMapperFileName("%sMapper")
                                    // mapperBuilder  END
                                    .serviceBuilder()
                                    .superServiceClass(properties.getSuperServiceClass())
                                    .superServiceImplClass(properties.getSuperServiceImplClass())
                                    .formatServiceFileName("%sService")
                                    .formatServiceImplFileName("%sServiceImpl")
                                    // serviceBuilder  END
                                    .controllerBuilder()
                                    .superClass(properties.getSuperControllerClass())
                                    .enableHyphenStyle()
                                    .enableRestStyle()
                                    .formatFileName("%sController");
                            // controllerBuilder  END
                        })
                        .injectionConfig(builder -> {
                            builder.beforeOutputFile((tableInfo, objectMap) -> {
                                System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size());
                            });
                        })
                        .execute();
            }
        };

    }


}
